package win.liumian.sso.filter;

import win.liumian.sso.util.CookieUtil;
import win.liumian.sso.util.SsoHttpClient;

import javax.servlet.*;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;

import static win.liumian.sso.util.Constants.*;


/**
 * @author liumian
 */
public class SsoFilter implements Filter {

    private SsoHttpClient httpClient;

    /**
     * 生成cookie的域名
     */
    private String domain;

    private String clientId;


    @Override
    public void init(FilterConfig filterConfig) {

        domain = filterConfig.getInitParameter(DOMAIN);
        clientId = filterConfig.getInitParameter(CLIENT_ID);
        httpClient = new SsoHttpClient();
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        String queryString = ((HttpServletRequest) request).getQueryString();
        StringBuffer requestURL = ((HttpServletRequest) request).getRequestURL();
        System.out.println("sso filter...." + requestURL + " * " + queryString);

        //检测header中是否携带ssoTicket
        String ssoTicket = request.getParameter(SSO_TICKET);
        if (ssoTicket == null || ssoTicket.isEmpty() || !isLegalTicket(ssoTicket)) {
            //尝试从cookie中获取登录凭证并验证
            Cookie[] cookies = ((HttpServletRequest) request).getCookies();
            Cookie ssoTicketCookie = getCookieFrom(cookies, SSO_TICKET);
            if (ssoTicketCookie == null) {
                doRedirect((HttpServletRequest) request, (HttpServletResponse) response);
            } else {
                //检测ticket是否合法
                boolean legalTicket = isLegalTicket(ssoTicketCookie.getValue());
                if (legalTicket) {
                    chain.doFilter(request, response);
                } else {
                    //销毁cookie并进行重定向
                    CookieUtil.destroyCookie((HttpServletResponse) response, SSO_TICKET, domain);
                    doRedirect((HttpServletRequest) request, (HttpServletResponse) response);
                }
            }
        } else {
            Cookie cookie = new Cookie(SSO_TICKET, ssoTicket);
            cookie.setMaxAge(MAX_AGE);
            ((HttpServletResponse) response).addCookie(cookie);

            if (queryString.contains(SSO_TICKET)) {
                boolean isFirst = true;
                String[] parameters = queryString.split("&");
                for (int i = 0; i < parameters.length; i++) {

                    if (!parameters[i].contains(SSO_TICKET)) {
                        if (isFirst) {
                            requestURL.append("?");
                            isFirst = false;
                        } else {
                            requestURL.append("&");
                        }
                        requestURL.append(parameters[i]);
                    }
                }
            }
            ((HttpServletResponse) response).sendRedirect(requestURL.toString());
        }

    }

    @Override
    public void destroy() {
        httpClient.destroy();
    }


    private Cookie getCookieFrom(Cookie[] cookies, String targetCookieName) {
        for (int i = 0; cookies != null && i < cookies.length; i++) {
            if (cookies[i].getName().equals(targetCookieName)) {
                return cookies[i];
            }
        }
        return null;
    }


    private boolean isLegalTicket(String ssoTicket) {
        return httpClient.isLegalTicket(ssoTicket);
    }

    private void doRedirect(HttpServletRequest request, HttpServletResponse response) throws IOException {
        response.sendRedirect(getRedirectUrl(request));
    }

    /**
     * 获取重定向URL，并进行encode
     *
     * @param request
     * @return encode后的URL
     * @throws UnsupportedEncodingException
     */
    private String getRedirectUrl(HttpServletRequest request) throws UnsupportedEncodingException {
        String encodeUrl = URLEncoder.encode(getOriginUrl(request), "UTF-8");
        return SSO_SERVER_URL + "?redirectUrl=" + encodeUrl + "&clientId=" + clientId;
    }


    /**
     * 获取原始URL
     *
     * @param request
     * @return
     */
    private String getOriginUrl(HttpServletRequest request) {
        String originUrl = request.getRequestURL().toString();
        String queryString = request.getQueryString();
        if (queryString != null && !queryString.equals("")) {
            originUrl = originUrl + "?" + queryString;
        }
        return originUrl;
    }

}
